#ifndef __WLPRIMITIVE_H__
#define __WLPRIMITIVE_H__
#include "WLResource.h"
class WLMaterial : public WLResource
{
public:
	void Serialize(class WLArchive& Ar){};
	std::string m_TexDiffuse;
	virtual int Build(){return 1;};

};

#include "WLArchive.h"
// Flexible vertex format bits
//
enum
{
	FVF_XYZ        =      0x002,
	FVF_XYZRHW     =      0x004,
	FVF_XYZB1      =      0x006,
	FVF_XYZB2      =      0x008,
	FVF_XYZB3      =      0x00a,
	FVF_XYZB4      =      0x00c,
	FVF_XYZB5      =      0x00e,
	FVF_XYZW       =      0x4002,
							  
	FVF_NORMAL     =      0x010,
	FVF_PSIZE      =      0x020,
	FVF_DIFFUSE    =      0x040,
	FVF_SPECULAR   =      0x080,
	FVF_TEX0       =      0x000,
	FVF_TEX1       =      0x100,
	FVF_TEX2       =      0x200,
	FVF_TEX3       =      0x300,
	FVF_TEX4       =      0x400,
	FVF_TEX5       =      0x500,
	FVF_TEX6       =      0x600,
	FVF_TEX7       =      0x700,
	FVF_TEX8       =      0x800 
};				  
 enum PRIMITIVETYPE {
    PT_POINTLIST             = 1,
    PT_LINELIST              = 2,
    PT_LINESTRIP             = 3,
    PT_TRIANGLELIST          = 4,
    PT_TRIANGLESTRIP         = 5,
    PT_TRIANGLEFAN           = 6,
 };			   
class WLMesh;	   
class WLPrimFace
{
public:
	WLPrimFace()
	{
	
	}
	WLPrimFace(const WLPrimFace& f)
	{
		VertIndex[0] = f.VertIndex[0];
		VertIndex[1] = f.VertIndex[1];
		VertIndex[2] = f.VertIndex[2];
	}
	WLPrimFace(int Index0, int Index1, int Index2)
	{
		VertIndex[0] = Index0;
		VertIndex[1] = Index1;
		VertIndex[2] = Index2;
	}
	int VertIndex[3];
};
// Linked list of vertex normals 
class VNormal 
{
   public: 

     WLVector3 norm; 

     DWORD smooth; 

     VNormal *next; 

     int init; 

     VNormal() {smooth=0;next=NULL;init=FALSE;norm=WLVector3(0,0,0);} 

     VNormal(WLVector3 &n,DWORD s) {next=NULL;init=TRUE;norm=n;smooth=s;} 

     ~VNormal() {delete next;} 

     void AddNormal(WLVector3 &n,DWORD s); 

     WLVector3 &GetNormal(DWORD s); 

     void Normalize(); 

};

template<class T>
WLArchive& operator << (WLArchive& Ar, std::vector<T>& DestVector )
{
	int Num = 0;
	Ar<<Num;
	
	for ( int i = 0; i<Num; i++ )
	{
		DestVector.push_back(T());
		Ar<<DestVector[i];	
	}
	return Ar;
}

WLArchive& operator << (WLArchive& Ar, WLPrimFace &Face );

class WLPrimData
{
public:
	WLPrimData()
	{
		m_pOwner = NULL;
		m_pMaterial = NULL;
	}
	class WLPrimitive* m_pOwner;

	std::vector<WLPrimFace> m_Faces;
	std::vector<WLVector3>	m_PositionData;
	std::vector<WLVector3>	m_NormalData;
	std::vector<WLVector3>	m_UVWData;
	std::vector<DWORD>		m_ColorData;
	std::vector<DWORD>		m_SmoothGroupArray;

	WLMaterial* m_pMaterial;
	
	PRIMITIVETYPE  m_PTType;
	int            m_PrimitiveCount;


	WLPrimData(WLPrimitive* Owner)
	{
		m_pOwner = Owner;
	}
	void SetOwner(WLPrimitive* Owner)
	{
		m_pOwner = Owner;
	}
	int BuildIndexPrimitive( std::vector<int>& FaceIDs, int Index, std::vector<int>& FaceSMs );
	int BuildPrimitive(int Index);
	void ComputeVertexNormals(std::vector<VNormal>& vnorms); 
	void SetPrimitiveType( PRIMITIVETYPE Type )
	{
		m_PTType = Type;
		
	}
	int GetPrimitiveCount()
	{
		return m_PrimitiveCount;
	}
	void SetPrimitiveCount(int Count)
	{
		m_PrimitiveCount = Count;
	}
	void* GetIndexStream()
	{
		return m_Faces.data();
	}

	unsigned int GetVertexSize()
	{
		unsigned int VerSize = 0;
		m_PositionData.size()>0?VerSize+=sizeof(WLVector3):VerSize += 0;
		m_NormalData.size()>0?VerSize+=sizeof(WLVector3):VerSize += 0;
		m_UVWData.size()>0?VerSize+=sizeof(WLVector3):VerSize += 0;
		m_ColorData.size()>0?VerSize+=sizeof(DWORD):VerSize += 0;
		return VerSize;
	}
	DWORD GetPrimitiveType()
	{
		return m_PTType;
	}
	DWORD GetFormat()
	{
		DWORD Format = 0;
		Format|= (FVF_XYZ*(m_PositionData.size()>0));
		Format|= (FVF_DIFFUSE*(m_ColorData.size()>0));
		Format|= (FVF_NORMAL*(m_NormalData.size()>0));
		Format|= (FVF_TEX1*(m_UVWData.size()>0));
		return Format;
	}
	WLVector3* GetPosition(int Index)
	{
		return &(m_PositionData[Index]);
	}
	WLVector3* GetNormal(int Index)
	{
		return &(m_NormalData[Index]);
	}
	WLVector3* GetUVW(int Index)
	{
		return &(m_UVWData[Index]);
	}
	DWORD* GetColor( int Index )
	{
		return &(m_ColorData[Index]);
	}
};

class WLPrimitive : public WLResource
{
protected:
	unsigned int Reversion;
public:
	int GetReversion()
	{
		return Reversion;
	}
	WLPrimitive()
	{
		Reversion = 0;
	}
	PRIMITIVETYPE m_PrimType;
	virtual WLMaterial& GetMaterial(int m)
	{
		return m_Materials[m];
	}
	virtual WLVector3* GetVert( int v )
	{
		return NULL;
	}
	virtual WLVector3* GetTVert( int t )
	{
		return NULL;
	}
	virtual WLPrimFace* GetFace(int f)
	{
		return NULL;
	}
	virtual WLPrimFace* GetTFace(int f)
	{
		return NULL;
	}
	virtual int* GetFaceSmoothGroup(int f)
	{
		return NULL;
	}
	std::vector<WLPrimData>& GetDataArray()
	{
		return m_DataArray;
	}
	void SetPrimitiveType(PRIMITIVETYPE Type)
	{
		m_PrimType = Type;
		for ( unsigned int i = 0; i<this->m_DataArray.size(); i++ )
		{
			m_DataArray[i].SetPrimitiveType(m_PrimType);
		}
	}
	PRIMITIVETYPE GetPrimitiveType()
	{
		return m_PrimType;
	}

	virtual int Build()
	{
		Reversion++;
		return 1;
	}
	virtual int PreRender(){return 0;}
	virtual int PostRender(){return 0;}
	unsigned int PrimCount;
	WLVector3 m_Location;
	WLQuaternion m_Rotation;
	
	std::vector<WLMaterial> m_Materials;
	std::vector<WLPrimData> m_DataArray;

};

class WLMesh : public WLPrimitive
{
	std::vector<WLVector3>	m_Verts;
	std::vector<WLPrimFace> m_Faces;
	std::vector<WLVector3>	m_UVWs;
	std::vector<WLPrimFace> m_TexFaces;
	std::vector<int>		m_FaceMatIndex;
	std::vector<int>		m_SmoothGroup;
public:

	WLVector3* GetVert( int v )
	{
		return &(m_Verts[v]);
	}
	WLVector3* GetTVert( int t )
	{
		return &(m_UVWs[t]);
	}
	WLPrimFace* GetFace(int f)
	{
		return &(m_Faces[f]);
	}
	WLPrimFace* GetTFace(int f)
	{
		return &(m_TexFaces[f]);
	}
	int* GetFaceSmoothGroup(int f)
	{
		return &(m_SmoothGroup[f]);
	}

	int Build();
	void Serialize(class WLArchive& Ar);
};
struct WLSkinData
{
	int BoneIndex;
	float Weight;
};
struct WLVertexSkin
{
	std::vector<WLSkinData> DataArray;
};

struct WLRawBoneData
{
	int Parent;
	std::string BoneName;
	WLVector3 Position;
};
WLArchive& operator << (WLArchive& Ar, WLRawBoneData &Bone );
WLArchive& operator << (WLArchive& Ar, WLVertexSkin &Skin );
WLArchive& operator << (WLArchive& Ar, WLSkinData &Skin );

class WLBoneMesh : public WLMesh
{
private:
	std::vector<WLRawBoneData> m_BoneArray;
	std::vector<std::string> m_SkinBoneArray;
	std::vector<WLVertexSkin> m_SkinDataArray;
public:
	int Build();
	void Serialize(class WLArchive& Ar);
	int PreRender(){return 0;}
	int PostRender(){return 0;}
};
class WLLineBatch : public WLPrimitive
{
public:
	void Serialize(WLArchive & Ar){}
	int Build();
	int AddLine( WLVector3 Start, WLVector3 End, DWORD Color );
};
extern WLLineBatch* g_pLineBatch;
class WLGrid : public WLPrimitive
{
private:
	float m_EdgeLength;
	int m_HalfSegCount;
public:
	int PreRender(){return 0;}
	int PostRender(){return 0;}

	WLGrid()
	{
	}
	WLGrid( float EdgeLength, int HalfSegCount )
	{
		m_EdgeLength = EdgeLength;
		m_HalfSegCount = HalfSegCount;
	}
	void Serialize(WLArchive & Ar){}
	int Build();
};

#endif